/*
 * 中介者模式（Mediator Pattern）是用来降低多个对象和类之间的通信复杂性。
 * 这种模式提供了一个中介类，该类通常处理不同类之间的通信，并支持松耦合，使代码易于维护。
 * 中介者模式属于行为型模式。
 *
 * 意图：用一个中介对象来封装一系列的对象交互，中介者使各对象不需要显式地相互引用，从而使其耦合松散，而且可以独立地改变它们之间的交互。
 *
 * 主要解决：对象与对象之间存在大量的关联关系，这样势必会导致系统的结构变得很复杂，同时若一个对象发生改变，我们也需要跟踪与之相关联的对象，同时做出相应的处理。
 *
 * 何时使用：多个类相互耦合，形成了网状结构。
 *
 * 如何解决：将上述网状结构分离为星型结构。
 *
 * 关键代码：对象 Colleague 之间的通信封装到一个类中单独处理。
 *
 * 应用实例： 1、中国加入 WTO 之前是各个国家相互贸易，结构复杂，现在是各个国家通过 WTO 来互相贸易。
 *           2、机场调度系统。
 *           3、MVC 框架，其中C（控制器）就是 M（模型）和 V（视图）的中介者。
 *
 * 优点： 1、降低了类的复杂度，将一对多转化成了一对一。
 *       2、各个类之间的解耦。
 *       3、符合迪米特原则。
 *
 * 缺点：中介者会庞大，变得复杂难以维护。
 *
 * 使用场景： 1、系统中对象之间存在比较复杂的引用关系，导致它们之间的依赖关系结构混乱而且难以复用该对象。
 *           2、想通过一个中间类来封装多个类中的行为，而又不想生成太多的子类。
 *
 * 注意事项：不应当在职责混乱的时候使用。
*/

/*
 * UML 图地址 “https://img-my.csdn.net/uploads/201108/9/0_1312892590zSzS.gif”
 * 这里就以租房为例子，如果没有房屋中介，那么房客要自己找房东，而房东也要自己找房客，非常不方便。
 * 有了房屋中介机构就方便了，房东可以把要出租的房屋信息放到中介机构，而房客可以去中介机构咨询。
 * 在软件中，就是多个对象之间需要通信，如果没有中介，对象就需要知道其他对象， 最坏情况下，可能需要知道所有其他对象，而有了中介对象就方便多了，对象只需与中介对象通信，而不用知道其他的对象。
*/

#include <iostream>
#include <string>
#include <vector>
#include <memory>
#include <algorithm>


using namespace std;

class Mediator;


/// 抽象人, 租客和房东都是Person的派生类
class Person: public std::enable_shared_from_this<Person>
{
public:
    Person(std::shared_ptr<Mediator> spMediator)
        :m_wpMediator(spMediator) {
    }
    virtual ~Person() {}
    virtual void SetMediator(std::shared_ptr<Mediator> spMediator) = 0;
    virtual void SendMessage(const string& message) = 0;
    virtual void GetMessage(const string& message) = 0;

protected:
    std::weak_ptr<Mediator> m_wpMediator; // 中介
};

/// 中介者, A表示房东，B表示租客
class Mediator
{
public:
    virtual void Send(string message, std::shared_ptr<Person> person) = 0;
    virtual void SetA(std::shared_ptr<Person> spPerson) = 0;  //设置其中一方
    virtual void SetB(std::shared_ptr<Person> spPerson) = 0;

protected:
    std::vector<std::shared_ptr<Person> > m_vecA; //租房者若干
    std::vector<std::shared_ptr<Person> > m_vecB; //房东若干

};

/// 租房者
class Renter: public Person
{
public:
    Renter(std::shared_ptr<Mediator> spMediator):Person(spMediator) {}
    void SetMediator(std::shared_ptr<Mediator> spMediator) {
        m_wpMediator = spMediator;
    }

    void SendMessage(const string& message) {
        if (auto spMediator = m_wpMediator.lock())
        {
            spMediator->Send(message, shared_from_this());
        }
    }

    void GetMessage(const string& message) {
        if (auto spMediator = m_wpMediator.lock())
        {
            cout << "租房者收到信息:" << message;
        }
    }
};

/// 房东
class Landlord: public Person
{
public:
    Landlord(std::shared_ptr<Mediator> spMediator):Person(spMediator) {}
    void SetMediator(std::shared_ptr<Mediator> spMediator) {
        m_wpMediator = spMediator;
    }
    void SendMessage(const string& message) {
        if (auto spMediator = m_wpMediator.lock())
        {
            spMediator->Send(message, shared_from_this());
        }
    }

    void GetMessage(const string& message) {
        if (auto spMediator = m_wpMediator.lock())
        {
            cout << "房东收到信息" << message;
        }
    }
};



/// 房屋中介
class HouseMediator: public Mediator
{
public:
    HouseMediator():Mediator() {}

    /// 获取租客
    std::shared_ptr<Person> GetA(size_t index) {
        return m_vecA[index];
    }
    void SetA(std::shared_ptr<Person> A) {
        m_vecA.push_back(A);
    }

    /// 获取房东
    std::shared_ptr<Person> GetB(size_t index) {
        return m_vecB[index];
    }
    void SetB(std::shared_ptr<Person> B) {
        m_vecB.push_back(B);
    }

    void Send(string message, std::shared_ptr<Person> person) {
        /// 判断person是租客还是房东
        auto ita = std::find(m_vecA.begin(), m_vecA.end(), person);
        if (ita != m_vecA.end())
        {
            /// person 是租客
            for (std::shared_ptr<Person> spB : m_vecB)
            {
                spB->GetMessage(message);  /// 发给所有房东
            }
        }

        auto itb = std::find(m_vecB.begin(), m_vecB.end(), person);
        if (itb != m_vecB.end())
        {
            /// person 是房东
            for (std::shared_ptr<Person> spA : m_vecA)
            {
                spA->GetMessage(message);  /// 发给所有租客
            }
        }
    }

};

int main()
{
    /// 创建 中介机构
    std::shared_ptr<HouseMediator> spMediator = std::make_shared<HouseMediator>();

    /// 创建房东 10个
    for (uint8_t i = 0; i < 10; ++i)
    {
        std::shared_ptr<Landlord> spLandlord = std::make_shared<Landlord>(spMediator);
        spMediator->SetB(spLandlord);
    }

    /// 创建租客 20个
    for (uint8_t i = 0; i < 20; ++i)
    {
        std::shared_ptr<Renter> spRenter = std::make_shared<Renter>(spMediator);
        spMediator->SetA(spRenter);
    }

    /// 有三个房东有房出租，分别是 1，6，8
    std::shared_ptr<Person> spB1 = spMediator->GetB(1);
    spB1->SendMessage("蜀湖湾 4#204 出租 2室一厅  80m*m 2000元一个月\n");
    std::shared_ptr<Person> spB6 = spMediator->GetB(6);
    spB6->SendMessage("祥源城 20#1202 出租 3室一厅 120m*m 3000元一个月\n");
    std::shared_ptr<Person> spB8 = spMediator->GetB(8);
    spB8->SendMessage("复兴家园 27#1204 出租 1室一厅 50m*m 1000元一个月\n");


    /// 租客要求租 5，7，13，17这4个租客要求租
    std::shared_ptr<Person> spA5 = spMediator->GetA(5);
    spA5->SendMessage("蜀湖湾 求租 2室一厅 价格1800元一个月\n");
    std::shared_ptr<Person> spA7 = spMediator->GetA(7);
    spA5->SendMessage("祥源城 求租 1室一厅 价格1200元一个月\n");
    std::shared_ptr<Person> spA13 = spMediator->GetA(13);
    spA5->SendMessage("祥源城 求租 2室一厅 价格1500元一个月\n");
    std::shared_ptr<Person> spA17 = spMediator->GetA(17);
    spA5->SendMessage("复兴家园 求租 3室一厅 价格3000元一个月\n");

    return 0;
}
